# -*- coding: UTF-8 -*-
# __author__ = 'Sengo'
import numpy as np
import math
from data_service import read_data


def calculation(c, p, v_prime, d=1.0, f=500.0, h=15.0):
    C = np.mat(c)
    P = np.mat(p)
    # N = 1/math.sqrt((P-C)*(P-C).T) * (P-C)
    N = (P-C) / np.linalg.norm(P - C)  # Z-axis
    N = N.tolist()[0]
    U = vertex_multiply(N, v_prime) / np.linalg.norm(vertex_multiply(N, v_prime))  # X-axis
    V = vertex_multiply(U, N)  # Y-axis
    U = U.tolist()
    print "C:", C
    print "Vprime:", v_prime
    print "P:", p
    print "================"
    print "N:", N
    print "U", U
    print "V", V
    print "==================="
    _U = U + [0]
    _V = V + [0]
    _N = N + [0]
    R = np.mat([_U, _V, _N, [0, 0, 0, 1]])
    T = np.mat([[1, 0, 0, -c[0]], [0, 1, 0, -c[1]], [0, 0, 1, -c[2]], [0, 0, 0, 1]])
    print "R:", R
    print "T:", T
    print "==================="
    M_view = R * T
    print "M_view:", M_view
    print "==================="
    M_pers = np.mat([[d/h, 0, 0, 0], [0, d/h, 0, 0], [0, 0, f/(f-d), -d*f/(f-d)], [0, 0, 1, 0]])
    print "M_pers:", M_pers
    print "==================="
    return M_view, M_pers


def transformation(c, p, v_prime, d=1.0, f=500.0, h=15.0, divide_w=False):
    M_view, M_pers = calculation(c, p, v_prime, d, f, h)
    vertexes, lines = read_data()

    # Mview * points
    view_vs = []
    for v in vertexes:
        v = v + [1]
        v = np.mat(v).T
        view_v = M_view * v
        view_v = view_v.T.tolist()[0]
        view_vs.append(view_v)
    print view_vs
    # normal of surface
    print "==========visible"
    visible_surfaces = []
    for face in lines:
        ves = []
        for v in face:
            ves.append(view_vs[v])
        if not ves:
            continue
        if len(ves) < 3:
            visible_surfaces.append(face)
            continue
        dot1 = np.mat(ves[0])
        dot2 = np.mat(ves[1])
        dot3 = np.mat(ves[2])
        line1 = dot2 - dot1
        line2 = dot3 - dot2
        line_of_sight = (np.mat([0, 0, 0]) - np.mat(ves[0][:-1])).tolist()[0]
        vertex1 = line1.tolist()[0][0:-1]
        vertex2 = line2.tolist()[0][0:-1]
        normal = vertex_multiply(vertex1, vertex2)
        print "normal:", normal
        visible = vertex_dot_multiply(normal, line_of_sight)
        print "visible (normal dot-multiply line-of-sight):", visible
        if visible > 0:
            visible_surfaces.append(face)
        print visible_surfaces
    print "=============="

    new_vs = []
    for v in vertexes:
        v = v + [1]
        v = np.mat(v).T
        new_v = M_pers * M_view * v
        new_v = new_v.T.tolist()[0]   # lists
        if divide_w:
            # X,Y,Z divide W
            new_v[0] = new_v[0] / new_v[-1]
            new_v[1] = new_v[1] / new_v[-1]
            new_v[2] = new_v[2] / new_v[-1]
        print new_v
        new_vs.append(new_v)
    return new_vs, visible_surfaces


def vertex_multiply(a, b):
    """a*b cross multiply"""
    ax = a[0]
    ay = a[1]
    az = a[2]
    bx = b[0]
    by = b[1]
    bz = b[2]
    cx = ay*bz - az*by
    cy = az*bx - ax*bz
    cz = ax*by - ay*bx
    return [cx, cy, cz]


def vertex_dot_multiply(a, b):
    ax = a[0]
    ay = a[1]
    az = a[2]
    bx = b[0]
    by = b[1]
    bz = b[2]
    return ax*bx + ay*by + az*bz


if __name__ == '__main__':
    C = [4.0, 6.0, 10.0]  # Camera position
    P = [0.0, 0.0, 0.0]
    V_prime = [0, 1, 0]  # Y-direction of camera
    # transformation(C, P, V_prime, d=10.0, f=100, h=15)
    a = [2, 3, 5]
    b = [0, 1, 0]
    # print  np.linalg.norm(vertex_multiply(a,b))
